"""
@Author: li
@Email: lijianqiao2906@live.com
@FileName: user.py
@DateTime: 2025/07/05
@Docs: 用户相关服务
"""

from datetime import UTC, datetime
from typing import cast

from tortoise.exceptions import DoesNotExist, IntegrityError
from tortoise.transactions import in_transaction

from app.core.exceptions import BadRequestException, ConflictException
from app.models import Role, User
from app.schemas import UserCreate, UserUpdate
from app.services.base import BaseService
from app.utils.logger import logger
from app.utils.security import get_password_hash


class UserService(BaseService):
    """用户服务"""

    def __init__(self):
        super().__init__(User)

    async def get_user_by_username(self, username: str) -> User | None:
        """根据用户名获取未删除的用户"""
        user = await self.dao.get_one(username=username, is_deleted=False)
        return cast(User, user) if user else None

    async def get_user_by_email(self, email: str) -> User | None:
        """根据邮箱获取未删除的用户"""
        user = await self.dao.get_one(email=email, is_deleted=False)
        return cast(User, user) if user else None

    async def get_user_by_username_or_email(self, username_or_email: str) -> User | None:
        """根据用户名或邮箱获取用户"""
        if "@" in username_or_email:
            return await self.get_user_by_email(username_or_email)
        return await self.get_user_by_username(username_or_email)

    async def get_user_with_roles(self, user_id: int) -> User | None:
        """根据用户ID获取用户，并预加载角色信息"""
        user_model = await self.dao.get_by_id_with_prefetch(user_id, "roles")
        return cast(User, user_model) if user_model else None

    async def create_user(self, user_in: UserCreate) -> User:
        """创建新用户"""
        if await self.dao.exists(username=user_in.username):
            raise ConflictException(f"用户名 '{user_in.username}' 已存在")
        if await self.dao.exists(email=user_in.email):
            raise ConflictException(f"邮箱 '{user_in.email}' 已存在")

        user_data = user_in.model_dump(exclude={"password", "role_ids"})
        user_data["password_hash"] = get_password_hash(user_in.password)

        try:
            async with in_transaction():
                created_user_model = await self.dao.create(**user_data)
                if not created_user_model:
                    raise BadRequestException("创建用户失败")
                created_user = cast(User, created_user_model)

                if user_in.role_ids:
                    await self.assign_roles(created_user.id, user_in.role_ids)

                return created_user
        except IntegrityError as e:
            logger.error(f"创建用户时发生数据库完整性错误: {e}")
            raise ConflictException("创建用户失败，可能存在唯一键冲突") from e

    async def update_user(self, user_id: int, user_in: UserUpdate) -> User:
        """更新用户信息"""
        update_data = user_in.model_dump(exclude_unset=True, exclude={"role_ids"})

        if "username" in update_data and await self.dao.exists(username=update_data["username"], id__not=user_id):
            raise ConflictException(f"用户名 '{update_data['username']}' 已被其他用户使用")
        if "email" in update_data and await self.dao.exists(email=update_data["email"], id__not=user_id):
            raise ConflictException(f"邮箱 '{update_data['email']}' 已被其他用户使用")

        async with in_transaction():
            updated_user_model = await self.dao.update_by_id(user_id, **update_data)
            if not updated_user_model:
                raise DoesNotExist("需要更新的用户不存在")
            updated_user = cast(User, updated_user_model)

            if user_in.role_ids is not None:
                await self.assign_roles(user_id, user_in.role_ids)

        return updated_user

    async def update_last_login(self, user_id: int) -> None:
        """更新用户最后登录时间"""
        await self.dao.update_by_id(user_id, last_login_at=datetime.now(UTC))

    async def get_user_permissions(self, user_id: int) -> list[str]:
        """获取用户所有权限编码列表"""
        user_model = await self.dao.get_by_id_with_prefetch(user_id, "roles__permissions")
        if not user_model:
            return []
        user = cast(User, user_model)
        permission_codes = {perm.code for role in user.roles for perm in role.permissions}
        return list(permission_codes)

    async def has_permission(self, user_id: int, permission_code: str) -> bool:
        """检查用户是否有指定权限"""
        user_permissions = await self.get_user_permissions(user_id)
        return permission_code in user_permissions

    async def assign_roles(self, user_id: int, role_ids: list[int]) -> User:
        """为用户分配角色"""
        try:
            async with in_transaction():
                user_model = await self.dao.get_by_id_with_prefetch(user_id, "roles")
                if not user_model:
                    raise DoesNotExist(f"用户 {user_id} 不存在")
                user = cast(User, user_model)

                roles = await Role.filter(id__in=role_ids, is_deleted=False)
                await user.roles.clear()
                await user.roles.add(*roles)

                logger.info(f"为用户 {user_id} 分配角色成功: {role_ids}")
                # 重新获取用户以包含更新的角色信息
                updated_user = await self.dao.get_by_id_with_prefetch(user_id, "roles")
                return cast(User, updated_user)
        except DoesNotExist as e:
            logger.error(f"为用户分配角色失败: {e}")
            raise
        except Exception as e:
            logger.error(f"为用户 {user_id} 分配角色时发生未知错误: {e}")
            raise

    async def create_superuser(self, user_in: UserCreate) -> User:
        """创建一个超级用户，并赋予所有角色"""
        # 1. 检查用户是否已存在
        if await self.dao.exists(username=user_in.username):
            raise ConflictException(f"用户名 '{user_in.username}' 已存在")
        if await self.dao.exists(email=user_in.email):
            raise ConflictException(f"邮箱 '{user_in.email}' 已存在")

        # 2. 准备用户数据
        user_data = user_in.model_dump(exclude={"password", "role_ids"})
        user_data["password_hash"] = get_password_hash(user_in.password)
        user_data["is_superuser"] = True  # 直接设置超管标志

        # 3. 在事务中创建用户并分配角色
        try:
            async with in_transaction():
                created_user_model = await self.dao.create(**user_data)
                if not created_user_model:
                    raise BadRequestException("创建超级用户失败")
                created_user = cast(User, created_user_model)

                # 4. 分配所有可用角色
                all_roles = await Role.filter(is_deleted=False)
                await created_user.roles.add(*all_roles)
                logger.info(f"超级用户 '{created_user.username}' 创建成功，并已赋予所有角色。")

                return created_user
        except IntegrityError as e:
            logger.error(f"创建超级用户时发生数据库完整性错误: {e}")
            raise ConflictException("创建超级用户失败，可能存在唯一键冲突") from e


user_service = UserService()
